﻿using DecisionCircle.Platform;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.ApplicationSettings;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237

namespace DecisionCircle.View
{
    /// <summary>
    /// A basic page that provides characteristics common to most applications.
    /// </summary>
    public sealed partial class PlayPage : DecisionCircle.Common.LayoutAwarePage
    {
        #region Variable
        Circle circle;
        DispatcherTimer timer;

        const uint SUPPORTEDCONTACTS = 1;
        uint numActiveContacts;
        Dictionary<uint, Point?> contacts;

        Random rand;
        bool blnStart = false;
        double dVo;
        double dOmega0;
        double dOmega;
        double dTime = 0;

        Point previoursPoint;
        Point currentPoint;
        ulong ulTimeChangePoint;
        int intRotate;
        bool blnIsPress;
        int intTypeDirect;
        bool blnIsAnimation = true;
        uint ptrId;

        #endregion

        #region Constructor

        public PlayPage()
        {
            numActiveContacts = 0;
            contacts = new Dictionary<uint, Point?>((int)SUPPORTEDCONTACTS);
            this.InitializeComponent();
            gridCircle.PointerPressed += new PointerEventHandler(gridCircle_PointerPressed);
            gridCircle.PointerReleased += new PointerEventHandler(gridCircle_PointerReleased);
            gridCircle.PointerMoved += new PointerEventHandler(gridCircle_PointerMoved);
            rand = new Random();

        }

        #endregion

        #region Initialize

        private void InitializeFeature()
        {
            InitializeConstant();
            InitializeCircle();
            InitializeTimer();
            InitializePlayerList();
        }

        private void InitializeConstant()
        {
            Constant.PointWidthHeightParent = new Point(gridCircle.Width, gridCircle.Height);
            #region Color
            Constant.ListColor = new List<Windows.UI.Color>() {
            Color.FromArgb(200,255,125,35),
            Color.FromArgb(120,0,255,0),
            Color.FromArgb(160,213,9,14),
            Color.FromArgb(120,255,255,0),
            Color.FromArgb(200,38,155,236),            
            Color.FromArgb(200,120,186,0),
            Color.FromArgb(150,48,5,216),
            Color.FromArgb(200,174,17,61),
            Color.FromArgb(200,244,179,0),
            Color.FromArgb(120,255,0,255),
            Color.FromArgb(150,174,47,206),
            Color.FromArgb(200,0,164,164),
            Color.FromArgb(150,21,0,79),
            Color.FromArgb(170,21,100,79),
            Color.FromArgb(140,0,21,15),
            Color.FromArgb(200,21,21,15),
            Color.FromArgb(200,70,180,0),
            Color.FromArgb(200,125,60,125),
            Color.FromArgb(200,128,64,0),
            Color.FromArgb(200,255,255,255)
            };
            #endregion
        }

        private void InitializeCircle()
        {
            gridCircle.Background = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));
            //Vị trí ban đầu của hình tròn
            circle = new Circle(1, Constant.IntCurrentNumOfPlayers, Constant.IntCurrentRadius, new Point(300, 50));
            circle.SetParent(ref gridCircle);
        }

        private void InitializePlayerList()
        {
            try
            {
                for (int i = 0; i < Constant.IntCurrentNumOfPlayers; i++)
                {
                    viewPLayer.Items.Add(new ColorData(Constant.ListColor[i], "Player " + (i + 1).ToString()));
                }
            }
            catch { }
        }

        private void InitializeTimer()
        {
            timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(1);
            timer.Tick += timer_Tick;
            timer.Start();
        }
        #endregion

        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="navigationParameter">The parameter value passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
        /// </param>
        /// <param name="pageState">A dictionary of state preserved by this page during an earlier
        /// session.  This will be null the first time a page is visited.</param>
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
        }

        /// <summary>
        /// Preserves state associated with this page in case the application is suspended or the
        /// page is discarded from the navigation cache.  Values must conform to the serialization
        /// requirements of <see cref="SuspensionManager.SessionState"/>.
        /// </summary>
        /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
        protected override void SaveState(Dictionary<String, Object> pageState)
        {
        }

        #region Event

        private void pageRoot_Loaded(object sender, RoutedEventArgs e)
        {
            InitializeFeature();
        }

        void timer_Tick(object sender, object e)
        {
            TimerCircle();

        }

        private void gridCircle_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            var pt = e.GetCurrentPoint(gridCircle);

            if (contacts.ContainsKey(pt.PointerId) && contacts[pt.PointerId].HasValue)
            {
                currentPoint = pt.Position;
                PointerMove();
            }

            e.Handled = true;
        }

        private void gridCircle_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            var ptrId = e.GetCurrentPoint(sender as FrameworkElement).PointerId;
            if (contacts.ContainsKey(ptrId))
            {
                PointerRelease(ptrId);
            }

            e.Handled = true;
        }

       
        private void gridCircle_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            if (numActiveContacts >= SUPPORTEDCONTACTS || blnStart)
            {
                numActiveContacts = 0;
                return;
            }

            var pt = e.GetCurrentPoint(gridCircle);
            e.Handled = true;

            PointerPress(pt);
        }

        #endregion

        #region Function

        private void TimerCircle()
        {
            if (blnIsPress && !blnStart)
            {
                HidePaneResult();
                ++ulTimeChangePoint;
                if (ulTimeChangePoint >= Constant.UlTimeSpanChangePoint)
                {
                    ulTimeChangePoint = 0;
                    int distance = (int)Physical.LengthVector(previoursPoint, currentPoint);
                    if (distance < 50)
                    {
                        intRotate = 1;
                    }
                    else
                    {
                        intRotate = 3;
                    }

                    previoursPoint = currentPoint;
                }
            }

            if (blnStart)
            {
                ++dTime;
                if (blnIsAnimation)
                {
                    blnIsAnimation = false;
                    CircleRotating1.Begin();
                }
                //Tốc độ góc giảm dần theo thời gian
                dOmega = Physical.Omega(dOmega0, dTime * Constant.DRatioOfRealTime);

                if (dOmega < 0)
                {
                    dOmega = 0;
                    blnStart = false;
                    SetTheChosenOne();
                    blnIsAnimation = true;
                    CircleRotating1.Stop();
                }

                //Truyền vận tốc như mong muốn tính theo độ
                circle.Rotate((int)dOmega * intTypeDirect);
            }

        }

        private void PointerPress(PointerPoint pt)
        {
            ptrId = pt.PointerId;
            contacts[ptrId] = pt.Position;
            previoursPoint = pt.Position;
            ++numActiveContacts;
            blnIsPress = true;
        }

        private void PointerRelease(uint ptrId)
        {
            contacts[ptrId] = null;
            contacts.Remove(ptrId);
            --numActiveContacts;

            blnStart = true;
            dOmega0 = Physical.Omega0(dVo, Constant.DRatioRadiusCircle);

            //Góc quay tối đa
            if (dOmega0 > Constant.IntMaxAngle)
            {
                dOmega0 = Constant.IntMaxAngle;
            }

            dOmega0 += rand.Next(100) % 7;
            dTime = 0;
            ulTimeChangePoint = 0;
            blnIsPress = false;

        }

        private void PointerMove()
        {
            var radius = Physical.LengthVector(circle.PointCenter, currentPoint);
            dVo = Physical.LengthVector(previoursPoint, currentPoint) / 7;
            SetInitPointer();
            if (currentPoint != previoursPoint)
            {
                circle.Rotate(intRotate * intTypeDirect);
            }

            if (radius >= Constant.DRadiusCircle)
            {
                PointerRelease(ptrId);
            }

            
        }

        private void SetInitPointer()
        {
            var prePtr = Physical.TransferCoordinates(previoursPoint, circle.PointCenter);
            var curPtr = Physical.TransferCoordinates(currentPoint, circle.PointCenter);
            int directPrePtr = Physical.DirectionPointer(prePtr);
            int directVector = Physical.DirectionPointer(new Point(curPtr.X - prePtr.X, curPtr.Y - prePtr.Y));

            if (directPrePtr == 1)
            {
                if (directVector == 4 || (prePtr.X > prePtr.Y && directVector == 3))
                {
                    intTypeDirect = 1;
                }
                else
                {
                    intTypeDirect = -1;
                }
            }

            if (directPrePtr == 4)
            {
                if (directVector == 3 || (prePtr.X > prePtr.Y && directVector == 2))
                {
                    intTypeDirect = 1;
                }
                else
                {
                    intTypeDirect = -1;
                }
            }

            if (directPrePtr == 3)
            {
                if (directVector == 2 || (prePtr.X < prePtr.Y && directVector == 1))
                {
                    intTypeDirect = 1;
                }
                else
                {
                    intTypeDirect = -1;
                }
            }

            if (directPrePtr == 2)
            {
                if (directVector == 1 || (prePtr.X < prePtr.Y && directVector == 4))
                {
                    intTypeDirect = 1;
                }
                else
                {
                    intTypeDirect = -1;
                }
            }      
        }

        private void SetTheChosenOne()
        {
            try
            {
                int indexOfTheChosen = circle.GetIndexOfTheChosenOne();

                var res = viewPLayer.Items[indexOfTheChosen] as ColorData;

                ShowPaneResult(res);
            }
            catch { }
        }

        private void ShowPaneResult(ColorData res)
        {
            ColorChosenOne.Fill = res.Color;
            NameChosenOne.Text = res.PlayerName;

            panelResult.Visibility = Windows.UI.Xaml.Visibility.Visible;
        }

        private void HidePaneResult()
        {
            panelResult.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
        }
        #endregion
    }
}
